﻿//---------------------------------------------------------------------
// <copyright file="ODataSimplifiedOptions.cs" company="Microsoft">
//      Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------

using System;

namespace Microsoft.OData
{
    /// <summary>
    /// Options which used to control the behaviour related odata simplified.
    /// </summary>
    public sealed class ODataSimplifiedOptions
    {
        // default setting for writing control information without a prefix
        private bool enableWritingODataAnnotationWithoutPrefix;

        // OData 4.0-specific setting for writing control information without a prefix
        private bool omitODataPrefix40 = false;

        // OData 4.01 and greater setting for writing control information without a prefix
        private bool omitODataPrefix = true;

        /// <summary>
        /// Constructor of ODataSimplifiedOptions
        /// </summary>
        public ODataSimplifiedOptions() : this(null /*version*/)
        {
        }

        /// <summary>
        /// Constructor of ODataSimplifiedOptions
        /// </summary>
        /// <param name="version">The ODataVersion to create Default Options for.</param>
        public ODataSimplifiedOptions(ODataVersion? version)
        {
            this.EnableParsingKeyAsSegmentUrl = true;
            this.EnableWritingKeyAsSegment = false;
            this.EnableReadingKeyAsSegment = false;

            if (version == null || version < ODataVersion.V401)
            {
                this.EnableReadingODataAnnotationWithoutPrefix = false;
                this.enableWritingODataAnnotationWithoutPrefix = this.omitODataPrefix40;
            }
            else
            {
                this.EnableReadingODataAnnotationWithoutPrefix = true;
                this.enableWritingODataAnnotationWithoutPrefix = this.omitODataPrefix;
            }
        }

        /// <summary>
        /// True if url parser support parsing path with key as segment, otherwise false. The defualt is true.
        /// </summary>
        public bool EnableParsingKeyAsSegmentUrl { get; set; }

        /// <summary>
        /// Gets or sets a value that indicates whether the reader should put key values in their own URI segment when automatically building URIs.
        /// If this value is false, automatically-generated URLs will take the form "../EntitySet('KeyValue')/..".
        /// If this value is true, automatically-generated URLs will take the form "../EntitySet/KeyValue/..".
        /// This setting only applies to URLs that are automatically generated by the <see cref="ODataMessageReader" /> and the URLs explicitly provided by the server won't be modified.
        /// </summary>
        public bool EnableReadingKeyAsSegment { get; set; }

        /// <summary>
        /// True if can read reserved annotation name without prefix 'odata.', otherwise false.
        /// The default value is false for OData 4.0 and true for OData 4.01.
        /// The option is applied during deserialization.
        /// </summary>
        public bool EnableReadingODataAnnotationWithoutPrefix { get; set; }

        /// <summary>
        /// Gets or sets a value that indicates whether the writer should put key values in their own URI segment when automatically building URIs.
        /// If this value is false, automatically-generated URLs will take the form "../EntitySet('KeyValue')/..".
        /// If this value is true, automatically-generated URLs will take the form "../EntitySet/KeyValue/..".
        /// This setting only applies to URLs that are automatically generated by the <see cref="ODataMessageWriter" /> and does not modify URLs explicitly provided by the user.
        /// </summary>
        public bool EnableWritingKeyAsSegment { get; set; }

        /// <summary>
        /// True if control information should be written without the prefix 'odata.', otherwise false.
        /// The default value is false for OData 4.0, true for OData 4.01.
        /// The option is applied during serialization.
        /// </summary>
        [Obsolete("Deprecated. Use Get/SetOmitODataPrefix()")]
        public bool EnableWritingODataAnnotationWithoutPrefix
        {
            get
            {
                return this.enableWritingODataAnnotationWithoutPrefix;
            }

            set
            {
                this.enableWritingODataAnnotationWithoutPrefix =
                this.omitODataPrefix =
                this.omitODataPrefix40 = value;
            }
        }

        /// <summary>
        /// Creates a shallow copy of this <see cref="ODataSimplifiedOptions"/>.
        /// </summary>
        /// <returns>A shallow copy of this <see cref="ODataSimplifiedOptions"/>.</returns>
        public ODataSimplifiedOptions Clone()
        {
            var copy = new ODataSimplifiedOptions();
            copy.CopyFrom(this);
            return copy;
        }

        /// <summary>
        /// Get whether to write OData control information without a prefix
        /// True if control information can be read without prefix 'odata.', otherwise false.
        /// The default value is false for OData 4.0 and true for OData 4.01.
        /// The option is applied during deserialization.
        /// </summary>
        /// <returns>Whether to omit the OData prefix for the specified version.</returns>
        public bool GetOmitODataPrefix()
        {
            return this.enableWritingODataAnnotationWithoutPrefix;
        }

        /// <summary>
        /// Version-specific behavior for writing OData control information without a prefix
        /// True if control information can be read without prefix 'odata.', otherwise false.
        /// The default value is false for OData 4.0 and true for OData 4.01.
        /// The option is applied during deserialization.
        /// </summary>
        /// <param name="version">The version of the version-specific behavior being requested.</param>
        /// <returns>Whether to omit the OData prefix for the specified version.</returns>
        public bool GetOmitODataPrefix(ODataVersion version)
        {
            if (version >= ODataVersion.V401)
            {
                return this.omitODataPrefix;
            }

            return this.omitODataPrefix40;
        }


        /// <summary>
        /// Whether to write OData control information without a prefix
        /// True to read control information without the prefix 'odata.', otherwise false.
        /// The default value is false for OData 4.0 and true for OData 4.01.
        /// The option is applied during deserialization.
        /// </summary>
        /// <param name="enabled">True to omit writing the OData prefix, False to write the prefix.</param>
        public void SetOmitODataPrefix(bool enabled)
        {
            this.enableWritingODataAnnotationWithoutPrefix =
            this.omitODataPrefix =
            this.omitODataPrefix40 = enabled;
        }

        /// <summary>
        /// Version-specific behavior for writing OData control information without a prefix
        /// True to read control information without the prefix 'odata.', otherwise false.
        /// The default value is false for OData 4.0 and true for OData 4.01.
        /// The option is applied during deserialization.
        /// </summary>
        /// <param name="enabled">True to omit writing the OData prefix, False to write the prefix.</param>
        /// <param name="version">The version for which to specify the omit prefix behavior.</param>
        public void SetOmitODataPrefix(bool enabled, ODataVersion version)
        {
            if (version == ODataVersion.V4)
            {
                this.omitODataPrefix40 = enabled;
            }
            else
            {
                this.omitODataPrefix = enabled;
            }
        }

        /// <summary>
        /// Return the instatnce of ODataSimplifiedOptions from container if it container not null.
        /// Otherwise return the static instance of ODataSimplifiedOptions.
        /// </summary>
        /// <param name="container">Container</param>
        /// <param name="version">OData Version</param>
        /// <returns>Instance of GetODataSimplifiedOptions</returns>
        internal static ODataSimplifiedOptions GetODataSimplifiedOptions(IServiceProvider container, ODataVersion? version = null)
        {
            if (container == null)
            {
                return new ODataSimplifiedOptions(version);
            }

            return container.GetRequiredService<ODataSimplifiedOptions>();
        }

        private void CopyFrom(ODataSimplifiedOptions other)
        {
            ExceptionUtils.CheckArgumentNotNull(other, "other");

            this.EnableParsingKeyAsSegmentUrl = other.EnableParsingKeyAsSegmentUrl;
            this.EnableReadingKeyAsSegment = other.EnableReadingKeyAsSegment;
            this.EnableReadingODataAnnotationWithoutPrefix = other.EnableReadingODataAnnotationWithoutPrefix;
            this.EnableWritingKeyAsSegment = other.EnableWritingKeyAsSegment;
            this.enableWritingODataAnnotationWithoutPrefix = other.enableWritingODataAnnotationWithoutPrefix;
            this.omitODataPrefix40 = other.omitODataPrefix40;
            this.omitODataPrefix = other.omitODataPrefix;
        }
    }
}
